package h;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sun.xml.internal.ws.util.StringUtils;

import b.Entity;


@SuppressWarnings("serial")
public class MaintenanceServlet extends HttpServlet {

	public static Pattern uriPattern;

	@Override
	public void init(){
		uriPattern = Pattern.compile("^"+this.getServletContext().getContextPath()+"/maint/([a-z][a-z0-9]*)/(\\d+|create)?$");
	}

	@Override
	public void doGet(HttpServletRequest request,HttpServletResponse response) {
		try{
			RouterToken rt=RouterToken.parse(request);
			if(rt!=null) {
				RequestContext rc =(RequestContext)request.getSession().getAttribute("Request-Context");

				if(rt.action==RouterToken.Action.List) {
					Iterator<Entity> entities=dispatchListRequest(rt,rc);
					if(entities!=null){
						request.setAttribute("Entities", entities);
						this.getServletContext().getRequestDispatcher("/list_"+rt.module.toLowerCase()+".jsp").forward(request, response);
						return;
					}
				} else {
					Entity en = dispatchRetrieveRequest(rt,rc);
					if(en!=null||rt.action==RouterToken.Action.Create) {
						request.setAttribute("Entity", en);
						this.getServletContext().getRequestDispatcher("/maint_"+rt.module.toLowerCase()+".jsp").forward(request, response);
						return;
					}
				}
			}

			response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
		} catch(Exception e){
			e.printStackTrace();
		}
	}

	@Override
	public void doPost(HttpServletRequest request,HttpServletResponse response) {
		try{
			RouterToken rt=RouterToken.parse(request);
			if(rt!=null) {
				Entity en = dispatchRetrieveRequest(rt,(RequestContext)request.getSession().getAttribute("Request-Context"));

				HashMap<String,String> paramsMap = new HashMap<String,String>();

				@SuppressWarnings("unchecked")
				Enumeration<String> pNames = request.getParameterNames();
				String pName;
				while(pNames.hasMoreElements()){
					paramsMap.put(pName=pNames.nextElement(), request.getParameter(pName));
				}

				en.update(paramsMap);
				boolean b = en.save();

				response.setContentType("text/plain");
				PrintWriter pw = response.getWriter();
				pw.append("{_:"+(b?0:1)+",UID:"+en.getId()+"}");
				return;
			}
			response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
		} catch(Exception e){
			e.printStackTrace();
		}
	}

	@SuppressWarnings("unchecked")
	private Iterator<Entity> dispatchListRequest(RouterToken rt,RequestContext rc) throws ServletException {
		Iterator<Entity> ens = null;
		try{
			Class<?> c = Class.forName("b."+rt.module);
			ens = (Iterator<Entity>)c.getDeclaredMethod("list",RequestContext.class).invoke(null, rc);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ens;
	}
	
	private Entity dispatchRetrieveRequest(RouterToken rt,RequestContext rc) throws ServletException {
		Entity en = null;
		try {
			Class<?> c = Class.forName("b."+rt.module);

			if(rt.action==RouterToken.Action.Update) {
				en = (Entity)c.getDeclaredMethod("retrieve", int.class).invoke(null, rt.id);
			} else if(rt.action==RouterToken.Action.Create) {
				en = (Entity)c.getDeclaredMethod("create",RequestContext.class).invoke(null,rc);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return en;
	}

	private static class RouterToken {
		String module;
		int id;
		Action action;

		public static RouterToken parse(HttpServletRequest request) {
			Matcher m = uriPattern.matcher(request.getRequestURI());
			RouterToken rt=null;
			if(m.matches()) {
				rt = new RouterToken();
				rt.module = StringUtils.capitalize(m.group(1));

				if(m.group(2)==null){
					rt.action = Action.List;
				} else if(m.group(2).equals("create")) {
					rt.action = Action.Create;
				} else {
					rt.action = Action.Update;
					rt.id = Integer.parseInt(m.group(2));
				}
			}
			return rt;
		}

		public enum Action {
			Create,Update,List
		}
	}
}
